﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using AlbinoHorse.Model;
using AlbinoHorse.ClassDesigner;
using System.Collections;
using AlbinoHorse.Layout;
using System.Drawing.Drawing2D;
//using System.Runtime.Serialization;
//using System.Runtime.Serialization.Formatters.Soap;
using System.Xml.Serialization;
using System.IO;
using System.Configuration;

namespace geraAplicacao
{
    public partial class frmModelo2 : Form
    {
        public frmModelo2()
        {
            InitializeComponent();
            classLookup = new Dictionary<string, Entity>();
            //umlLookup = new Dictionary<string, UmlType>();
        }
        private bool setPrimary = false;
        Dictionary<string, Entity> classLookup;
        Dictionary<string, UmlType> umlLookup; 
        public frmModelo2(string arquivo)
        {
            InitializeComponent();

            classLookup = new Dictionary<string, Entity>();
            umlLookup = new Dictionary<string, UmlType>();
            open3(arquivo);
        }

        ////Binário
        //internal void save4(string caminho)
        //{

        //    //Serializar
        //    using (System.IO.FileStream fs = new System.IO.FileStream(caminho, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write))  
        //     {  
        //         System.Runtime.Serialization.Formatters.Binary.BinaryFormatter b = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
        //         b.Serialize(fs, umlDesigner1.Diagram);  
        //         fs.Close();  
        //     } 
        //}
        //private void open4(string caminho)
        //{
        //    using (System.IO.FileStream ds = new System.IO.FileStream(caminho, System.IO.FileMode.Open, System.IO.FileAccess.Read))  
        //    {  
        //        System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
        //        umlDesigner1.Diagram = bf.Deserialize(ds) as UmlDiagram;      
        //    }  
        //}

        internal void save3(string caminho)
        {
            ////Serializar
            //System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(List<Shape>));
            //using (System.IO.FileStream xmlStream = new System.IO.FileStream(caminho, System.IO.FileMode.Create, System.IO.FileAccess.Write))
            //{
            //    serializer.Serialize(xmlStream, umlDesigner1.Diagram.Shapes);
            //    xmlStream.Close();
            //}
            AlbinoHorse.ClassDesigner.Persist.DiagramPersist pers = new AlbinoHorse.ClassDesigner.Persist.DiagramPersist();
            pers.save(umlDesigner1.Diagram.Shapes,caminho);
            this.Text = caminho;

        }

        private string derivaGeral(String texto)
        {
            StringBuilder sbResult = new StringBuilder(texto);
            //Retira acentos
            string comAcentos = "ÄÅÁÂÀÃäáâàãÉÊËÈéêëèÍÎÏÌíîïìÖÓÔÒÕöóôòõÜÚÛüúûùÇç";
            string semAcentos = "AAAAAAaaaaaEEEEeeeeIIIIiiiiOOOOOoooooUUUuuuuCc";
            for (int i = 0; i < comAcentos.Length; i++)
            {
                sbResult.Replace(comAcentos[i].ToString(), semAcentos[i].ToString());
            }
            //Retira preposições
            string[] preposicoes = {"a","de", "em", "para", "com", "por", "pelo", "pela",  "do", "da"};
            for (int i = 0; i < preposicoes.Length; i++)
            {
                sbResult.Replace(" " + preposicoes[i] + " "," ");
            }
            //Iniciais em maiúscula
            sbResult.Replace("  ", " ");
            String[] lsPalavras = sbResult.ToString().Split(' ');
            sbResult = new StringBuilder();
            foreach (String asPalavra in lsPalavras)
            {
                sbResult.Append(asPalavra.Substring(0, 1).ToUpper());
                sbResult.Append(asPalavra.Substring(1).ToLower());
            }

            return sbResult.ToString();
        }

        //Crias mecanismo de derviação de nomes por regex ou interface
        private string deriveTableName(String asNome)
        {
            return derivaGeral(asNome);
        }
        private string deriveColumName(String asNome)
        {
            return derivaGeral(asNome);
        }
        private string deriveLGName(String asNome)
        {
            return derivaGeral(asNome);
        }
        

        internal void generate()
        {
            ////Serializar
            //System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(List<Shape>));
            //using (System.IO.FileStream xmlStream = new System.IO.FileStream(caminho, System.IO.FileMode.Create, System.IO.FileAccess.Write))
            //{
            //    serializer.Serialize(xmlStream, umlDesigner1.Diagram.Shapes);
            //    xmlStream.Close();
            //}

            //frmOpcoes lfrmOpcoes = new frmOpcoes(true);
            String TiposTextuais = ConfigurationManager.AppSettings["TiposTextuais"];
            String TamanhoPadraoTexto = ConfigurationManager.AppSettings["TamanhoPadraoTexto"];

            frmGenerate lfrmGenerate = new frmGenerate();
            foreach (Shape shape in umlDesigner1.Diagram.Shapes)
            {
                if (shape is UmlType)
                {
                    UmlType loType = (UmlType)shape;



                    Entidades.EntidadeRow entidade = lfrmGenerate.entidades1.Entidade.NewEntidadeRow();
                    //entidade.Tabela = row["Tablename"].ToString();
                    entidade.Tabela = deriveTableName(loType.TypeName);
                    entidade.Descricao = loType.TypeName;
                    entidade.Nome = deriveLGName(loType.TypeName);
                    lfrmGenerate.entidades1.Entidade.AddEntidadeRow(entidade);
                    
                    //TODO: testar a herança entre entidades
                    UmlType loTypeProperties = loType;
                    while(loTypeProperties!=null)
                    {
                        foreach (UmlProperty loProperty in loTypeProperties.Properties.Members)
                        {
                            Entidades.PropriedadeRow propriedade = lfrmGenerate.entidades1.Propriedade.NewPropriedadeRow();
                            propriedade.Legenda = loProperty.Name;
                            propriedade.Nome = deriveLGName(loProperty.Name);
                            propriedade.Coluna = deriveColumName(loProperty.Name);
                            propriedade.Tipo = loProperty.Type;
                            propriedade.IsId = loProperty.IsKey;
                            propriedade.ManyToOne = false;
                            propriedade.Tamanho = loProperty.Size;
                            
                            //Atribui tamanho padrão para tipos textuais
                            if ((String.IsNullOrEmpty(propriedade.Tamanho)) && (TiposTextuais.IndexOf(loProperty.Type) >= 0))
                            {
                                propriedade.Tamanho = TamanhoPadraoTexto;
                            }

                            foreach (Shape shape2 in umlDesigner1.Diagram.Shapes)
                            {
                                if (shape2 is UmlType)
                                {
                                     UmlType loType2 = (UmlType)shape2;
                                    if(loProperty.Type.Equals(loType2.TypeName))
                                    {
                                        propriedade.ManyToOne = true;
                                        propriedade.NomeEntidadeEstrangeira = loType2.TypeName;
                                        foreach (UmlProperty loProperty2 in loType2.Properties.Members)
                                        {
                                            if (loProperty2.IsKey == true)
                                            {
                                                propriedade.AtributoValorExtrangeira = deriveLGName(loProperty2.Name);
                                                propriedade.Tipo = loProperty2.Type;  
                                            }
                                            else {
                                                if (String.IsNullOrEmpty(propriedade.AtributoExibicaoExtrangeira) && (TiposTextuais.IndexOf(loProperty2.Type) >= 0))
                                                {
                                                    propriedade.AtributoExibicaoExtrangeira = deriveLGName(loProperty2.Name);
                                                    break;
                                                }
                                            }
                                        }
                                        break;
                                    }
                                }
                            }

                            propriedade.SetParentRow(entidade);
                            lfrmGenerate.entidades1.Propriedade.AddPropriedadeRow(propriedade);
                        }
                        loTypeProperties = loTypeProperties.InheritsType;
                    }
                    


                }
                else if (shape is UmlConnection)
                {
                    //llUmlConnections.Add((UmlConnection)shape);
                }
            }
            lfrmGenerate.ShowDialog();

        }

        private void open3(string caminho)
        {
            //System.Xml.Serialization.XmlSerializer dxml = new System.Xml.Serialization.XmlSerializer(typeof(List<Shape>));
            //using (System.IO.FileStream xmlStream = new System.IO.FileStream(caminho, System.IO.FileMode.Open, System.IO.FileAccess.Read))
            //{
            //    umlDesigner1.Diagram.Shapes   = dxml.Deserialize(xmlStream) as List<Shape>;
            //    xmlStream.Close();
            //}  
            AlbinoHorse.ClassDesigner.Persist.DiagramPersist pers = new AlbinoHorse.ClassDesigner.Persist.DiagramPersist();
            List<Shape> shapes =pers.open(caminho);
            Dictionary<String, UmlType> lookUpType = new Dictionary<string, UmlType>();

            foreach (Shape shape in shapes)
            {
                if (shape is UmlType)
                {
                    UmlType newClass = (UmlType)shape;
                    newClass.SelectedObjectChanged += new EventHandler(Entidade_Change);
                    umlDesigner1.Diagram.Shapes.Add(newClass);
                    lookUpType.Add(newClass.TypeName, newClass);
                }
            }
            foreach (Shape shape in shapes)
            {
                if (shape is UmlConnection)
                {
                    UmlConnection conn = (UmlConnection)shape;

                    UmlType start;
                    bool lbResult = lookUpType.TryGetValue(((UmlType)conn.Start).TypeName, out start);
                    UmlType end;
                    bool lbResult2 = lookUpType.TryGetValue(((UmlType)conn.End).TypeName, out end);
                    if (lbResult && lbResult2)
                    {
                        conn.Start = start;
                        conn.End = end;
                        umlDesigner1.Diagram.Shapes.Add(conn);
                    }
                }
                else {
                    UmlType newClass = (UmlType)shape;

                    if (newClass.InheritsType != null)
                    {
                        UmlType curClass, paiClass;
                        bool lbResult = lookUpType.TryGetValue(newClass.TypeName, out curClass);
                        bool lbResult2 = lookUpType.TryGetValue(newClass.InheritsType.TypeName, out paiClass);
                        if (lbResult && lbResult2)
                        {
                            curClass.InheritsType = paiClass;
                        }
                    }
                }
            }
            umlDesigner1.Refresh();

            umlDesigner1.RefreshShapes();
            umlDesigner1.Refresh();
        }
        //private void open2(string arquivo)
        //{
        //     //definindo o formato e criando uma instância da classe SoapFormatter  
        //    IFormatter formato = new  SoapFormatter();       

        //    //definindo o Stream de onde será lido o arquivo .xml
        //    Stream file = new FileStream(arquivo,
        //    FileMode.Open ,FileAccess.Read , FileShare.Read );

        //    //agora sim, vamos desserializar o objeto
        //    classLookup = (Dictionary<string,Entity>)formato.Deserialize(file);

        //    //Stream fechado
        //    file.Close();  
            
        //    //Atualiza view
        //    foreach (Entity entity in classLookup.Values)
        //    {
        //        UmlType umlClass = new UmlType();
        //        umlClass.TypeName = entity.ClassName;
        //        if (!String.IsNullOrEmpty(entity.Inheritance))
        //        {
        //            UmlType umlClassInheritance;
        //            if (umlLookup.TryGetValue(entity.ClassName, out umlClassInheritance))
        //                umlClass.InheritsType = umlClassInheritance;
        //        }
        //        umlClass.SelectedObjectChanged += new EventHandler(Entidade_Change);
        //        foreach(EntityProperty property in entity.Properties)
        //        {
        //            UmlProperty umlProperty = new UmlProperty();
        //            umlProperty.Name = property.Name;
        //            umlProperty.Type = property.LangType;
        //            umlClass.Properties.Members.Add(umlProperty);
        //        }
        //        umlClass.Methods.Visible = false;
        //        umlClass.Bounds = new Rectangle(0, 0, 200, 10);
        //        umlClass.Expanded = true;
        //        umlLookup.Add(umlClass.TypeName, umlClass);
        //        umlDesigner1.Diagram.Shapes.Add(umlClass);
        //    }
        //    umlDesigner1.AutoLayout();
        //}

        private void open(string arquivo)
        {
            Entidades entidades1 = new Entidades();
            entidades1.Clear();
            entidades1.ReadXml(arquivo);

            #region percorre entidades

            foreach (DataRow tabela in entidades1.Tables["Entidade"].Rows)
            {
                Entity entity = new Entity();
                entity.ClassName = tabela["Nome"].ToString();
                entity.HumanName = tabela["Descricao"].ToString();
                entity.TableName = tabela["Tabela"].ToString();
                entity.Inheritance = tabela["Pai"].ToString();

                UmlType umlClass = new UmlType();
                umlClass.TypeName = entity.ClassName;

                //Necessário segundo loop para atribuir relacionamentos
                //if (!String.IsNullOrEmpty(entity.Inheritance))
                //{
                //    UmlType umlClassInheritance;
                //    if (umlLookup.TryGetValue(entity.ClassName, out umlClassInheritance))
                //        umlClass.InheritsType = umlClassInheritance;
                //}
                umlClass.SelectedObjectChanged += new EventHandler(Entidade_Change);

                ////ler do dataset
                DataRow[] colunas = tabela.GetChildRows("Entidade_Propriedade");

                foreach (DataRow coluna in colunas)
                {
                    EntityProperty property = new EntityProperty();
                    property.ColumnName = coluna["Campo"].ToString();
                    property.IsUnique = coluna["IsID"].ToString().Equals("true");
                    property.Name = coluna["Nome"].ToString();
                    property.HumanName = coluna["Legenda"].ToString();

                    String tipoLingagem;
                    DataRow[] tiposLinguagem = coluna.GetChildRows("Propriedade_TipoDado");
                    if (tiposLinguagem.Length == 0)
                        throw new Exception("Tipo de dado '" + coluna["Tipo"].ToString() + "' não está associação à um tipo de dado na linguagem");
                    tipoLingagem = tiposLinguagem[0]["TipoLinguagem"].ToString();
                    property.LangType = tipoLingagem;
                    entity.Properties.Add(property);

                    UmlProperty umlProperty = new UmlProperty();
                    umlProperty.Name = property.Name;
                    umlProperty.Type = property.LangType;
                    umlClass.Properties.Members.Add(umlProperty);
                }



                umlClass.Methods.Visible = false;
                //umlClass.Bounds = new Rectangle(0, 0, 200, 10);
                umlClass.Expanded = true;

                umlLookup.Add(umlClass.TypeName, umlClass);
                umlDesigner1.Diagram.Shapes.Add(umlClass);
                classLookup.Add(entity.ClassName, entity);
            }

            umlDesigner1.AutoLayout();

            //Realiza associações
            //foreach (IClassMap classMap in dm.ClassMaps)
            //{
            //    foreach (IPropertyMap propertyMap in classMap.PropertyMaps)
            //    {
            //        if (propertyMap.ReferenceType != Puzzle.NPersist.Framework.Enumerations.ReferenceType.None)
            //        {
            //            UmlType start = (UmlType)classLookup[classMap.Name];
            //            UmlType end = (UmlType)classLookup[propertyMap.DataType];
            //            UmlConnection umlConnection = new UmlConnection();
            //            umlConnection.Start = start;
            //            umlConnection.End = end;
            //            umlDesigner1.Diagram.Shapes.Add(umlConnection);
            //        }
            //    }
            //}
            #endregion percorre entidades
        }
        UmlType lUltimaEntidade;
        bool lbIniciouFiliacao;
        private void Entidade_Change(object sender, EventArgs e)
        {
            if (sender.GetType() == typeof(UmlType))
            {
                UmlType umlTemp = (UmlType)sender;
                if (lbIniciouFiliacao)
                {
                    lUltimaEntidade.InheritsType = umlTemp;

                    UmlConnection connection1 = new UmlConnection();
                    connection1.Start = lUltimaEntidade;
                    connection1.End = umlTemp;
                    umlDesigner1.Diagram.Shapes.Add(connection1);

                    lbIniciouFiliacao = false;
                }
                else {
                    lUltimaEntidade = umlTemp;
                }
                


            //    Entity entity;
            //    if (classLookup.TryGetValue(umlTemp.TypeName, out entity))
            //    {
            //        //propertyGrid1.SelectedObject = entity;
            //    }
            //    else 
            //    {
            //        entity = new Entity();
            //        entity.ClassName = umlTemp.TypeName;
            //        classLookup.Add(entity.ClassName, entity);
            //    }
            //}
            //else if (sender.GetType() == typeof(UmlProperty))
            //{
            //    UmlProperty umlTemp = (UmlProperty)sender;

            //    Entity entity;
            //    if (classLookup.TryGetValue(umlTemp.Name, out entity))
            //    {
            //        //propertyGrid1.SelectedObject = entity;
            //    }

            }
            else if ((setPrimary==true) && (sender.GetType() == typeof(UmlProperty)))
            {
                UmlProperty umlTemp = (UmlProperty)sender;
                umlTemp.IsKey = !umlTemp.IsKey;
            }
            //System.Console.WriteLine("disprou");  
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            
        }

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            umlDesigner1.AutoLayout();
        }

        private void toolStripComboBox1_Click(object sender, EventArgs e)
        {
           
        }

        private void toolStripComboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            string text = toolStripComboBox1.SelectedItem.ToString ();
            if (text == "")
                return;

            int zoom = Convert.ToInt32(text);
            double dzoom = (double)zoom / 100;
            umlDesigner1.Zoom = dzoom;
        }

        private void toolStripButton2_Click(object sender, EventArgs e)
        {
            UmlType newClass = new UmlType();
            newClass.Bounds = new Rectangle(1 * 21, 1 * 21, 7 * 21, 2 * 21);
            newClass.TypeName = "NovaEntidade";
            newClass.Methods.Visible = false;  
            umlDesigner1.Diagram.Shapes.Add(newClass);
            newClass.SelectedObjectChanged += new EventHandler(Entidade_Change);
            umlDesigner1.Refresh();
        }

        private void PropertyGrid1_PropertyValueChanged(object sender, PropertyValueChangedEventArgs e)
        {
            Object objectTmp = ((PropertyGrid)sender).SelectedObject;
            if (objectTmp.GetType() == typeof(Entity))
            {
                Entity entity = (Entity)objectTmp;
                //Classe Mudou de nome
                if (!classLookup.Remove(entity.ClassName))
                {
                    UmlType novoTipo;
                    classLookup.Remove(e.OldValue.ToString());
                    umlLookup.TryGetValue(e.OldValue.ToString(), out novoTipo);
                    umlLookup.Remove(e.OldValue.ToString());
                    novoTipo.TypeName = entity.ClassName;
                    
                    //Herança
                    UmlType inherType;
                    umlLookup.TryGetValue(entity.Inheritance, out inherType);
                    if (inherType != null)
                        novoTipo.InheritsType = inherType;

                    umlLookup.Add(novoTipo.TypeName, novoTipo);
                    classLookup.Add(entity.ClassName, entity);
                }
                else
                {

                }

            }
            //if (e.ChangedItem. )
            //{
            //    MessageBox.Show("n");
            //}
        }

        #region Método salvar
        //internal void save2(string caminho)
        //{
        //    //define o formato criando uma instância da classe SoapFormatter  
        //    IFormatter formato = new SoapFormatter();

        //    //definindo o Stream onde será salvo o xml com o estado do objeto
        //    // (neste caso, será criado na pasta Debug/Release do projeto
        //    Stream file = new FileStream(caminho,
        //    FileMode.Create,FileAccess.Write, FileShare.None);

        //    //agora sim, vamos serializar o objeto
        //    formato.Serialize(file, classLookup);

        //    //Stream fechado
        //    file.Close(); 
        //}
        internal void save(string caminho)
        {
            Entidades entidades1 = new Entidades();
            entidades1.Clear();
            int liContador = 1;

            foreach(Entity entity in classLookup.Values)
            {
                DataRow dw = entidades1.Tables["Entidades"].NewRow();
                dw["Nome"] = entity.ClassName;
                dw["Id"] = liContador;
                dw["Descricao"] = entity.HumanName;
                dw["Tabela"] = entity.TableName;
                dw["Pai"] = entity.Inheritance;

                entidades1.Tables["Entidades"].Rows.Add(dw);

                // classe.TypeName  = entidades1.Tables["Entidades"].Columns["Nome"].ToString();
                foreach (EntityProperty property in entity.Properties)
                 {
                     DataRow dwFilho = entidades1.Tables["Propriedade"].NewRow();
                     dwFilho["Entidade_id"] = liContador;
                     dwFilho["Nome"] = property.Name;
                     dwFilho["Tipo"] = property.LangType;
                     dwFilho["IsID"] = property.IsUnique;
                     dwFilho["Coluna"] = property.ColumnName;
                     dwFilho["Legenda"] = property.HumanName;

                     entidades1.Tables["Propriedade"].Rows.Add(dwFilho);
                 }
                 liContador++;
            }
            entidades1.WriteXml(caminho);
        }
        #endregion

        #region PartialName
        private string CompositeName(string Description, string ClassName, string TableName)
        {
            return Description + "<" + ClassName + ":" + TableName + ">";
        }

        enum NamePart { Description, ClassName, TableName }
        private string PartialName(string fullName, NamePart part)
        {
            if (part == NamePart.Description)
            {
                int liPos = fullName.IndexOf('<');
                if (liPos > 0)
                {
                    return fullName.Substring(0, liPos - 1);
                } else {
                    return fullName;
                }
            }
            else if (part == NamePart.ClassName)
            {
                int liPos = fullName.IndexOf('<');
                if (liPos > 0)
                {
                    int liPos2 = fullName.IndexOf(':');
                    if (liPos2 <= 0)
                        return fullName.Substring(liPos + 1).Replace(">", "");
                    else
                        return fullName.Substring(liPos + 1, liPos2 - liPos);
                }
                else
                {
                    return fullName;
                }
            }
            else 
            {
                int liPos = fullName.IndexOf('<');
                if (liPos > 0)
                {
                    int liPos2 = fullName.IndexOf(':');
                    if (liPos2 <= 0)
                        return fullName.Substring(liPos + 1).Replace(">", "");
                    else
                        return fullName.Substring(liPos2 + 1).Replace(">", "");
                }
                else
                {
                    return fullName;
                }                
            
            }
        }
        #endregion

        private void toolStripButton3_Click(object sender, EventArgs e)
        {
            lbIniciouFiliacao = true;
        }

        private void toolStripButton4_Click(object sender, EventArgs e)
        {
            setPrimary = !setPrimary;
            ((ToolStripButton)sender).Checked = setPrimary;
        }

    }
}
